package com.polaris.server.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.polaris.common.utils.RespBean;
import com.polaris.common.utils.StringUtils;
import com.polaris.server.bo.AdminUserDetails;
import com.polaris.security.util.JwtTokenUtil;
import com.polaris.server.mapper.LogLoginMapper;
import com.polaris.server.mapper.SysUserMapper;
import com.polaris.server.dto.UserCreateParam;
import com.polaris.server.pojo.LogLogin;
import com.polaris.server.pojo.SysMenu;
import com.polaris.server.pojo.SysUser;
import com.polaris.server.service.IAdminService;
import com.polaris.server.service.ISysUserRoleService;
import io.swagger.annotations.ApiOperation;
import io.swagger.annotations.ApiResponse;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 后台管理Service的具体实现类
 * @author CNPolaris
 * @version 1.0
 */
@ApiOperation(value = "登陆等相关业务的具体实现类")
@Service
public class IAdminServiceImpl extends ServiceImpl<SysUserMapper, SysUser> implements IAdminService {
    private final UserDetailsService userDetailsService;
    private final ISysUserRoleService userRoleService;
    private final PasswordEncoder passwordEncoder;
    private final JwtTokenUtil jwtTokenUtil;
    private final SysUserMapper userMapper;
    private final LogLoginMapper logLoginMapper;
    @Value("${jwt.tokenHead}")
    private String tokenHead;
    public IAdminServiceImpl(UserDetailsService userDetailsService, PasswordEncoder passwordEncoder, JwtTokenUtil jwtTokenUtil, SysUserMapper userMapper, ISysUserRoleService userRoleService, LogLoginMapper logLoginMapper) {
        this.userDetailsService = userDetailsService;
        this.passwordEncoder = passwordEncoder;
        this.jwtTokenUtil = jwtTokenUtil;
        this.userMapper = userMapper;
        this.userRoleService = userRoleService;
        this.logLoginMapper = logLoginMapper;
    }

    /**
     * 登陆之后返回token
     * @param username
     * @param password
     * @param request
     * @return
     */
    @ApiResponse(code = 2000,message = "登陆")
    @Override
    public RespBean login(String username, String password, HttpServletRequest request){
        //登陆
        String token = null;
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        if (userDetails == null || ! passwordEncoder.matches(password, userDetails.getPassword())) {
            return RespBean.error("用户名或密码不正确");
        }
        //用户是否禁用
        if(!userDetails.isEnabled()){
            return RespBean.error("账号被禁用,请联系管理员");
        }
        // 更新security登陆对象
        UsernamePasswordAuthenticationToken authenticationToken = new UsernamePasswordAuthenticationToken(userDetails, null,userDetails.getAuthorities());
        SecurityContextHolder.getContext().setAuthentication(authenticationToken);
        // 生成Token
        try {
            token = jwtTokenUtil.generatorToken(userDetails);
            insertLoginLog(username);
            refreshLoginTime(username);
        } catch (Exception e){
            log.debug(e.getMessage());
        }
        Map<String,String> tokenMap = new HashMap<>();
        tokenMap.put("token",token);
        tokenMap.put("tokenHead", tokenHead);
        return RespBean.success("登陆成功", tokenMap);
    }

    /**
     * 添加登陆记录
     * @param username
     */
    private void insertLoginLog(String username){
        SysUser sysUser = getAdminByUserName(username);
        if(sysUser==null) {
            return;
        }
        LogLogin logLogin = new LogLogin();
        logLogin.setAdminId(sysUser.getUserId());
        ServletRequestAttributes attributes = (ServletRequestAttributes) RequestContextHolder.getRequestAttributes();
        assert attributes != null;
        HttpServletRequest request = attributes.getRequest();
        String ip = StringUtils.getIp(request);
        logLogin.setIp(ip);
        logLogin.setAddress(StringUtils.getCityInfo(ip));
        logLogin.setUserAgent(StringUtils.getBrowser(request));
        logLogin.setCreateTime(new Date());
        logLoginMapper.insert(logLogin);
    }
    /**
     * 刷新token的具体实现类
     * @param token
     * @return
     */
    @Override
    public String refreshToken(String token) {
        return jwtTokenUtil.refreshToken(token);
    }

    /**
     * 根据用户名获取用户
     * @param username
     * @return
     */
    @Override
    public SysUser getAdminByUserName(String username){
        return userMapper.selectOne(new QueryWrapper<SysUser>().eq("username", username));
    }
    /**
     * @Description refreshLoginTime 登陆成功后刷新最近一次的登陆时间
     * @date 2021/5/14
     * @param username
     * @return void
     **/
    @Override
    public void refreshLoginTime(String username) {
        SysUser user = getAdminByUserName(username);
        userMapper.updateById(user);
    }

    /**
     * 管理创建新用户的具体实现
     * @param userCreateParam
     * @return
     */
    @Override
    public RespBean create(UserCreateParam userCreateParam) {
        SysUser user = new SysUser();
        BeanUtils.copyProperties(userCreateParam, user);
        QueryWrapper<SysUser> queryWrapper = new QueryWrapper<>();
        queryWrapper.eq("username", user.getUsername());
        if(userMapper.selectCount(queryWrapper)>0){
            return RespBean.error("用户名重复,请重试");
        }
        String encodePassword = passwordEncoder.encode(user.getPassword());
        user.setPassword(encodePassword);
        user.setEnable(1);
        userMapper.insert(user);
        return RespBean.success("创建新用户成功",user);
    }

    /**
     * 管理员删除用户的具体实现
     * @param id
     * @return RespBean
     */
    @Override
    public RespBean delete(Integer id) {
        try {
            QueryWrapper<SysUser> objectQueryWrapper = new QueryWrapper<>();
            objectQueryWrapper.eq("user_id",id);
            if(userMapper.selectCount(objectQueryWrapper)==0){
                return RespBean.error("id为"+id+"的用户不存在");
            }
            userMapper.deleteById(id);
            return RespBean.success("删除用户成功");
        }
        catch (Exception e){
            return RespBean.error("用户删除失败",e);
        }
    }

    /**
     * 管理员修改用户账户状态
     *
     * @param id
     * @param enable
     * @return RespBean
     */
    @Override
    public RespBean updateEnable(Integer id, Integer enable) {
        if(enable!=1 && enable!=0){
            return RespBean.error("指定修改字段违法");
        }
        try{
            SysUser users = userMapper.selectById(id);
            users.setEnable(enable);
            userMapper.updateById(users);
            Map<String, Object> data = new HashMap<>();
            data.put("enable", users.getEnable());
            data.put("username", users.getUsername());
            return RespBean.success("用户状态修改成功",data);
        }
        catch (Exception e){
            return RespBean.error("id为"+id+"的用户不存在");
        }
    }
    public List<SysMenu> getMenuList(Long userId){
        return userRoleService.getMenuList(userId);
    }


    /**
     * 通过用户名获取用户详情
     * @param username
     * @return
     */
    @Override
    public UserDetails loadUserByUsername(String username){
        SysUser admin = getAdminByUserName(username);
        if(admin!=null){
            List<SysMenu> menuList = getMenuList(admin.getUserId());
            return new AdminUserDetails(admin,menuList);
        }
        throw new UsernameNotFoundException("用户名或密码错误");
    }

}
